package br.academia.negocio;

import java.util.Collection;

import org.hibernate.HibernateException;

import br.academia.arq.dao.ExercicioTreinoDAO;
import br.academia.arq.dao.TreinoDAO;
import br.academia.arq.erros.DAOException;
import br.academia.arq.erros.NegocioException;
import br.academia.dominio.ExercicioTreino;
import br.academia.dominio.Treino;
import br.academia.util.Validador;

/** 
 * Processador para validação de negócio de operações
 * relacionadas a Treino
 * 
 * @see Treino
 */
public class TreinoProcessador extends AbstractProcessador<Treino>{

	@Override
	public void execute(TipoOperacao operacao, Treino obj) throws NegocioException{
		try {
			if(operacao.equals(CADASTRAR)){
				validarCadastro(obj);
				cadastrar(obj);
			}else if(operacao.equals(ALTERAR)){
				validarAlteracao(obj);
				alterar(obj);
			}else if(operacao.equals(REMOVER)){
				validarRemocao(obj);
				remover(obj);
			}
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new NegocioException("Não foi possível realizar a operação. Contate a administração do sistema.");
		} catch (DAOException e) {
			throw new NegocioException(e.getMessage());
		}
	}
	
	/**
	 * Método que valida se o nome setado em uma Série já tem um correspondente
	 * com relação à sigla, no banco de dados.
	 * @param obj
	 * @throws NegocioException
	 * @throws HibernateException
	 * @throws DAOException
	 */
	private void validarNome(Treino obj) throws NegocioException, HibernateException, DAOException{
		TreinoDAO dao = null;
		boolean erro = false;
		
		try {
			dao = getDAO(TreinoDAO.class);
			
			Treino treino = dao.findTreinoByNome(obj.getNome());
			
			if(!Validador.isEmpty(treino)){
				if(treino.getId() != obj.getId()){
					erro = true;
				}
			}
			
			if(erro){
				throw new NegocioException("Um outro Treino já foi cadastrado com o nome \"" + obj.getNome() + "\".");
			}
		}finally{
			if(dao != null){
				dao.close();
			}
		}
	}
	
	/**
	 * Método que faz as validações necessárias para o cadastro
	 * de uma Série novo no banco de dados.
	 * @param obj
	 * @throws HibernateException
	 * @throws NegocioException
	 * @throws DAOException
	 */
	private void validarCadastro(Treino obj) throws HibernateException, NegocioException, DAOException{
		validarNome(obj);
	}
	
	/**
	 * Método que insere uma Série no banco de dados.
	 * @param obj
	 * @throws NegocioException
	 * @throws HibernateException
	 * @throws DAOException
	 */
	private void cadastrar(Treino obj) throws NegocioException, HibernateException, DAOException{
		TreinoDAO dao = null;
		
		try {
			dao = getDAO(TreinoDAO.class);
			
			dao.save(obj);
		}finally{
			if(dao != null){
				dao.close();
			}
		}
	}
	
	/**
	 * Método que faz as validações necessárias para a alteração
	 * de uma Série no banco de dados.
	 * @param obj
	 * @throws HibernateException
	 * @throws NegocioException
	 * @throws DAOException
	 */
	private void validarAlteracao(Treino obj) throws NegocioException, HibernateException, DAOException{
		if(Validador.isEmpty(obj)){
			throw new NegocioException("Você selecionou uma Série inválido.");
		}else{
			TreinoDAO dao = null;
			Treino treino = null;
			
			try {
				dao = getDAO(TreinoDAO.class);
				
				treino = dao.findTreinoByNome(obj.getNome());
			}finally{
				if(dao != null){
					dao.close();
				}
			}
			
			if(!Validador.isEmpty(treino)){
				validarNome(obj);
			}
		}
	}
	
	/**
	 * Método que atualiza uma Série no banco de dados.
	 * @param obj
	 * @throws HibernateException
	 * @throws NegocioException
	 * @throws DAOException
	 */
	private void alterar(Treino obj) throws NegocioException, HibernateException, DAOException{
		TreinoDAO dao = null;
		
		try {
			dao = getDAO(TreinoDAO.class);
			
			dao.update(obj);
		}finally{
			if(dao != null){
				dao.close();
			}
		}
	}
	
	/**
	 * Método que faz as validações necessárias para a remoção
	 * de uma Série no banco de dados.
	 * @param obj
	 * @throws HibernateException
	 * @throws NegocioException
	 * @throws DAOException
	 */
	private void validarRemocao(Treino obj) throws NegocioException, HibernateException, DAOException{
		if(Validador.isEmpty(obj)){
			throw new NegocioException("Você selecionou uma Série inválido.");
		}else{
			TreinoDAO dao = null;
			Treino Treino = null;
			
			try {
				dao = getDAO(TreinoDAO.class);
				
				Treino = dao.findByPrimaryKey(obj.getId(), Treino.class);
			}finally{
				if(dao != null){
					dao.close();
				}
			}
			
			if(Validador.isEmpty(Treino)){
				throw new NegocioException("Não foi possível encontrar o Treino selecionado no nosso banco de dados.");
			}
		}
	}
	
	/**
	 * Método que remove uma Série do banco de dados.
	 * @param obj
	 * @throws HibernateException
	 * @throws NegocioException
	 * @throws DAOException
	 */
	private void remover(Treino obj) throws NegocioException, HibernateException, DAOException{
		TreinoDAO dao = null;
		ExercicioTreinoDAO exercicioTreinoDao = null;
		
		Collection<ExercicioTreino> exercicioTreinos = null;
		
		try {
			dao = getDAO(TreinoDAO.class);
			exercicioTreinoDao = getDAO(ExercicioTreinoDAO.class);
			
			exercicioTreinos = exercicioTreinoDao.findExerciciosByTreino(obj);
			
			if(!Validador.isEmpty(exercicioTreinos)){
				ExercicioTreinoProcessador processador = new ExercicioTreinoProcessador();
				
				for(ExercicioTreino m:exercicioTreinos){
					processador.execute(AbstractProcessador.REMOVER, m);
				}
			}
			
			dao.delete(obj);
		}finally{
			if(dao != null){
				dao.close();
			}
		}
	}
}
